﻿Ext.util.Event = Ext.extend(Object, (function () {

    //缓冲运行
    //handler：延迟运行的函数
    //
    //
    //scope：函数的作用域
    function createBuffered(handler, listener, o, scope) {
        listener.task = new Ext.util.DelayedTask();
        return function () {
            //o.buffer：延迟毫秒数；
            //handler：（可选的） 重写传入到构建器的函数
            //scope：重写传入到构建器的作用域
            //Ext.toArray(arguments)：（可选的） 重写传入到构建器的参数
            listener.task.delay(o.buffer, handler, scope, Ext.toArray(arguments));
        };
    };

    /* 
    createDelayed方法是先延迟指定时间，然后去执行任务，每个任务一定会执行。
    而createBuffered函数则不同，如果在其buffer时间里多次触发同一事件监听函数，
    那么它只执行最后一次触发的任务。
    */

    //推迟运行
    function createDelayed(handler, listener, o, scope) {
        return function () {
            var task = new Ext.util.DelayedTask();
            if (!listener.tasks) {
                listener.tasks = [];
            }
            listener.tasks.push(task);
            task.delay(o.delay || 10, handler, scope, Ext.toArray(arguments));
        };
    };

    //该监听函数只运行一次
    function createSingle(handler, listener, o, scope) {
        return function () {
            listener.ev.removeListener(listener.fn, scope);
            return handler.apply(scope, arguments);
        };
    }; 

    //真正返回的配置对象
    return {
        isEvent: true,

        //构造函数
        constructor: function (observable, name) {
            this.name = name;//事件名
            this.observable = observable;//作用域
            this.listeners = [];//多个监听函数的集合
        },

        //存放监听函数
        //options是存放延迟类型的对象，options.delay表示延迟运行，其数值表示延迟时间
        //options.buffer表示缓冲运行，其数值表示延迟时间，options.single表示只运行一次
        addListener: function (fn, scope, options) {
            var me = this,
                listener;
            scope = scope || me.observable;//作用域

            //判断fn参数是否已经有同作用域的函数存在
            if (!me.isListening(fn, scope)) {//如果没有
                //生成监听函数对象
                listener = me.createListener(fn, scope, options);

                if (me.firing) {//如果监听函数正在执行，为了不改变事件监听函数集合，
                    me.listeners = me.listeners.slice(0);//重新复制当前集合，然后赋给listeners属性，
                }
                me.listeners.push(listener);//并传入新增的监听函数。
            }
        },

        /// <summary>
        /// 生成监听函数对象
        /// </summary>
        /// <param name="fn">监听函数</param>
        /// <param name="scope">作用域</param>
        /// <param name="o">配置选项</param>
        /// <return></return>
        createListener: function (fn, scope, o) {
            o = o || {};
            scope = scope || this.observable;

            var listener = {
                fn: fn,
                scope: scope,
                o: o,
                ev: this
            },
                handler = fn;

            if (o.delay) {//是否推迟运行（推迟运行运行所有的延迟）
                handler = createDelayed(handler, listener, o, scope);
            }
            if (o.buffer) {//是否缓冲运行（缓冲运行运行最后一次产生的延迟）
                handler = createBuffered(handler, listener, o, scope);
            }
            if (o.single) {//该监听函数是否只运行一次
                handler = createSingle(handler, listener, o, scope);
            }

            listener.fireFn = handler;
            return listener;
        },

        //如果在this.listeners集合中找到函数名为fn，作用域为scope的，返回其下标，如果没找到则返回-1
        findListener: function (fn, scope) {
            var listeners = this.listeners,
            i = listeners.length,
            listener,
            s;

            while (i--) {
                listener = listeners[i];
                if (listener) {
                    s = listener.scope;
                    if (listener.fn == fn && (s == scope || s == this.observable)) {
                        return i;
                    }
                }
            }

            return -1;
        },

        //如果在this.listeners集合中找到函数名为fn，作用域为scope的，返回true，否则返回false
        isListening: function (fn, scope) {
            return this.findListener(fn, scope) !== -1;
        },

        //删除作用域为scope的fn函数的所有延迟运行、缓冲运行设置,移除监听函数
        removeListener: function (fn, scope) {
            var me = this,
                index,
                listener,
                k;
            index = me.findListener(fn, scope);//index为作用域为scope的fn函数在this.listeners中的索引
            if (index != -1) {//如果作用域为scope的fn函数在this.listeners中
                listener = me.listeners[index];

                if (me.firing) {//如果监听函数正在执行，为了不改变事件监听函数集合，
                    me.listeners = me.listeners.slice(0); //重新复制当前集合，然后赋给listeners属性
                }


                if (listener.task) {//撤销“缓冲运行”
                    listener.task.cancel();
                    delete listener.task;
                }


                k = listener.tasks && listener.tasks.length;
                if (k) {
                    while (k--) {//撤销“推迟运行”
                        //在用推迟运行时，fn有多少次等待，listener.tasks[]数值就有多少个元素，
                        //所以必须遍历撤销
                        listener.tasks[k].cancel(); 
                    }
                    delete listener.tasks;
                }

                //从index处开始删除1个数组元素
                me.listeners.splice(index, 1);
                return true;
            }

            return false;
        },

        //清除Ext.util.Event对象的所有延迟任务
        clearListeners: function () {
            var listeners = this.listeners,
                i = listeners.length;

            while (i--) {
                this.removeListener(listeners[i].fn, listeners[i].scope);
            }
        },

        //执行监听函数
        fire: function () {
            var me = this,
                listeners = me.listeners,//监听函数集合
                count = listeners.length,
                i,
                args,
                listener;

            if (count > 0) {
                me.firing = true;//表明正在执行
                for (i = 0; i < count; i++) {
                    listener = listeners[i];
                    args = arguments.length ? Array.prototype.slice.call(arguments, 0) : [];//把参数转化成数组赋给args
                    if (listener.o) {
                        args.push(listener.o);//将linstener的配置选项添加到args上
                    }
                    //fireFn在createListener方法中封装：listener.fireFn = handler;
                    if (listener && listener.fireFn.apply(listener.scope || me.observable, args) === false) {
                        return (me.firing = false);
                    }
                }
            }
            me.firing = false;
            return true;
        }
    };
})());